home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume5 / pt.bsd < prev    next >
Encoding:
Internet Message Format  |  1989-02-03  |  16.4 KB

  1. Path: xanth!nic.MR.NET!hal!ncoast!allbery
  2. From: lew@gsg.UUCP (Paul Lew)
  3. Newsgroups: comp.sources.misc
  4. Subject: v05i084: submission to comp.sources.misc
  5. Message-ID: <8812161819.AA28588@gsg.UUCP>
  6. Date: 19 Dec 88 00:18:22 GMT
  7. Sender: allbery@ncoast.UUCP
  8. Reply-To: lew@gsg.UUCP (Paul Lew)
  9. Lines: 521
  10. Approved: allbery@ncoast.UUCP
  11.  
  12. Posting-number: Volume 5, Issue 84
  13. Submitted-by: "Paul Lew" <lew@gsg.UUCP>
  14. Archive-name: pt.bsd
  15.  
  16. Newsgroups: comp.sources.misc
  17. Keywords: ps BSD process tree
  18. Message-ID: <290@gsg.UUCP>
  19. Date: 16 Dec 88 17:39:57 GMT
  20. Organization: General Systems Group, Inc., Salem, NH
  21. Lines: 511
  22.  
  23.     ptree,pt: BSD ps backend filter to display process tree
  24.  
  25. #! /bin/sh
  26. # This is a shell archive, meaning:
  27. # 1. Remove everything above the #! /bin/sh line.
  28. # 2. Save the resulting text in a file.
  29. # 3. Execute the file with /bin/sh (not csh) to create the files:
  30. #    README
  31. #    ptree.c
  32. #    Kill
  33. # This archive created: Fri Dec 16 12:22:07 1988
  34. export PATH; PATH=/bin:$PATH
  35. echo shar: extracting "'README'" '(2009 characters)'
  36. if test -f 'README'
  37. then
  38.     echo shar: will not over-write existing file "'README'"
  39. else
  40. sed 's/^    X//' << \SHAR_EOF > 'README'
  41.     X            Ptree Version 1.0  05/24/88
  42.     X
  43.     XIntroduction:
  44.     X
  45.     X    ptree is  a backend filter  for  BSD  'ps' command.  It  reads the
  46.     X    output from  ps and produces  process tree  graph on the  standard
  47.     X    output with each process indented under its  parent.  This program
  48.     X    was inspired by  the 'utree' program  for  system V  from  Brandon
  49.     X    Allbery.  The following is an example:
  50.     X
  51.     X      $ ptree ag | grep -v getty
  52.     X      USER STAT TTY  TIME COMMAND
  53.     X       lew I    i14  0:09 -Tcsh (Tcsh)
  54.     X       lew I    i14  0:31 |  emacs
  55.     X       lew I    p0   0:00 |  |  /usr/local/emacs/etc/loadst -n 60
  56.     X     alice I    i17  0:03 -csh (csh)
  57.     X       lew I    i18  0:08 -Tcsh (Tcsh)
  58.     X       lew S    i18  0:09 |  screen -e?]
  59.     X       lew I    p1   0:06 |  |  -bin/Tcsh (Tcsh)
  60.     X       lew S    p2   0:07 |  |  -bin/Tcsh (Tcsh)
  61.     X    domino S    i26  0:05 -csh (csh)
  62.     X    domino S    i26  0:00 |  lprint -f /usr/local/bin/lprint -n BigBucks
  63.     X    domino S    i26  0:00 |  |  dcat -d 3 -b 128
  64.     X       mxt I    i27  0:02 -csh (csh)
  65.     X       mxt I    i27  0:03 |  mail -f
  66.     X       mxt I    i27  0:00 |  |  sh -c /usr/ucb/more
  67.     X       mxt I    i27  0:00 |  |  |  /usr/ucb/more
  68.     X
  69.     X    This is not 'yet another setuid program'.  You dont have to be the
  70.     X    root to use it.  This is the main reason  to write it as a filter.
  71.     X    May be BSD can incorporate this into real 'ps' on future release.
  72.     X
  73.     X    Kill is a script which uses 'sf' (shell form in comp.sources.unix)
  74.     X    to allow one to send signals to processes by context.
  75.     X
  76.     XManual:
  77.     X
  78.     X    There is no man page to it, type: 'pt H' will give you simple help
  79.     X    message.  If you know how 'ps' works then you  dont need a manual,
  80.     X    if you dont, this might not be useful to you.
  81.     X
  82.     XBuild:
  83.     X
  84.     X    cc -o ptree ptree.c
  85.     X    ln ptree pt
  86.     X
  87.     XCopyright:
  88.     X
  89.     X    No copyright, complete in public domain. Do whatever you like with
  90.     X    it.  If you can make money from it, great for you.
  91.     X
  92.     X----------------------------------------------------------------------
  93.     XPaul Lew            {olivea,harvard,decvax}!gsg!lew    (UUCP)
  94.     XGeneral Systems Group, 5 Manor Parkway, Salem, NH 03079    (603) 893-1000
  95. SHAR_EOF
  96. if test 2009 -ne "`wc -c < 'README'`"
  97. then
  98.     echo shar: error transmitting "'README'" '(should have been 2009 characters)'
  99. fi
  100. fi # end of overwriting check
  101. echo shar: extracting "'ptree.c'" '(8883 characters)'
  102. if test -f 'ptree.c'
  103. then
  104.     echo shar: will not over-write existing file "'ptree.c'"
  105. else
  106. sed 's/^    X//' << \SHAR_EOF > 'ptree.c'
  107.     Xstatic    char    *Sccsid = "(File: %M%  Ver: %I%  Update: %G% %U%)";
  108.     X/*+F***********************************************************************
  109.     X*
  110.     X* File name:    ptree.c
  111.     X*
  112.     X* Author:    Paul Lew, General Systems Group, Inc. Salem, NH
  113.     X* Created at:    05/22/88  16:10 PM
  114.     X* Last update:    05/24/88  08:54 PM  (Edition: 26)
  115.     X*
  116.     X* Description:    This program will parse output of 'ps' command and display
  117.     X*        the output with process indented under their parents for
  118.     X*        the easy identification.
  119.     X*    
  120.     X* Environment:    4.2 BSD Unix (Pyramid OSx 4.1)
  121.     X*
  122.     X* Usage:    ptree [HPacgxt#]
  123.     X*
  124.     X* Update History:
  125.     X*
  126.     X*      Date        Description                    By
  127.     X*    --------    ------------------------------------------------    ---
  128.     X*    05/22/88    Initial version                        Lew
  129.     X*
  130.     X* Routines included:
  131.     X*
  132.     X*    build_offset    build offset from 1st line of ps output    
  133.     X*    save_addr    return addr of Save array with pid = pid    
  134.     X*    add_child    add child to parent, if exists, add to end of sibling
  135.     X*    print_result    display result
  136.     X*    print_process    print a given process sub-tree
  137.     X*    dump_save    dump save structure for debugging
  138.     X*    procarg        return command argument for ps command
  139.     X*    usage        display help message
  140.     X*
  141.     X* Build:    cc -o ptree ptree.c <CR>
  142.     X*
  143.     X**-F**********************************************************************/
  144.     X
  145.     X#include    <stdio.h>
  146.     X#include    <pwd.h>
  147.     X
  148.     X#define    YES        1
  149.     X#define    NO        0
  150.     X
  151.     X#define    MAXLINE        200
  152.     X
  153.     Xstruct    save    {
  154.     X    struct    save    *so_parent;    /* pointer to parent */
  155.     X    struct    save    *so_sibling;    /* pointer to 1st sibling */
  156.     X    struct    save    *so_child;    /* pointer to 1st child */
  157.     X    int        so_uid;        /* user ID */
  158.     X    char        so_name[9];    /* user name */
  159.     X    int        so_pid;        /* pid */
  160.     X    int        so_ppid;    /* parent pid */
  161.     X    char        *so_buffer;    /* pointer to ps output */
  162.     X    } Save [MAXLINE];
  163.     X
  164.     Xchar    *Version = "Version 1.0  05/24/88  00:51 AM";
  165.     Xchar    *Author = "Paul Lew, lew@gsg.uucp";
  166.     X
  167.     Xint    Line;                /* # of output line from ps */
  168.     Xint    Print_me = NO;            /* if NO, dont print my processes */
  169.     Xint    Print_pid = NO;            /* if YES, output PID */
  170.     Xchar    Command [80];
  171.     Xint    My_pid;                /* my process id */
  172.     X
  173.     Xint    Uid_offset;
  174.     Xint    Pid_offset;
  175.     Xint    Ppid_offset;
  176.     Xint    End_ppid;
  177.     Xint    Stat_offset;
  178.     Xint    Tyy_offset;
  179.     Xint    Command_offset;
  180.     X
  181.     Xstruct    save    *save_addr ();
  182.     Xchar        *procarg ();
  183.     X
  184.     Xextern    FILE    *popen ();
  185.     Xextern    char    *malloc (), *calloc ();
  186.     X
  187.     X/*-------------------------------------------------------------05/23/88-+
  188.     X|                                    |
  189.     X|      M a i n     R o u t i n e     S t a r t s     H e r e        |
  190.     X|                                    |
  191.     X+----------------------------------------------------------------------*/
  192.     Xmain (argc, argv)
  193.     Xint    argc;
  194.     Xchar    **argv;
  195.     X    {
  196.     X    FILE            *pfd;    /* file descriptor for popen() */
  197.     X    char            *p;    /* temp pointer to malloced buffer */
  198.     X    register int        i;    /* loop index */
  199.     X    register struct    save    *svp;
  200.     X
  201.     X    p = procarg (argc, argv);
  202.     X    sprintf (Command, "ps lw%s", p);
  203.     X    if ((pfd = popen (Command, "r")) == NULL) {
  204.     X        fprintf (stderr, "can not execture ps\n");
  205.     X        exit (1);
  206.     X        }
  207.     X    for (Line=0; Line<MAXLINE; Line++) {
  208.     X        p = malloc (BUFSIZ);
  209.     X        if (p == NULL) {
  210.     X            perror ("malloc");
  211.     X            exit (1);
  212.     X            }
  213.     X        if (fgets (p, BUFSIZ, pfd) == NULL) break;
  214.     X        Save[Line].so_buffer = p;
  215.     X        if (Line == 0) build_offset (p);
  216.     X        else            /* prevent CP data being processed */
  217.     X            p[End_ppid] = '\0';
  218.     X        }
  219.     X    pclose (pfd);
  220.     X    for (i=1; i<Line; i++) {
  221.     X        struct    passwd    *pwp;
  222.     X        svp = &Save[i];
  223.     X        svp->so_pid  = atoi (&svp->so_buffer[Pid_offset]);
  224.     X        svp->so_ppid = atoi (&svp->so_buffer[Ppid_offset]);
  225.     X        svp->so_uid  = atoi (&svp->so_buffer[Uid_offset]);
  226.     X        pwp = getpwuid (svp->so_uid);
  227.     X        strncpy (svp->so_name, pwp->pw_name, 8);
  228.     X        }
  229.     X    for (i=1; i<Line; i++) {
  230.     X        struct    save    *p;
  231.     X        svp = &Save[i];
  232.     X        svp->so_parent = p = save_addr (svp->so_ppid);
  233.     X        if (p) {
  234.     X            add_child (p, svp);
  235.     X            }
  236.     X        }
  237.     X    print_result ();
  238.     X#ifdef    DEBUG
  239.     X    dump_save ();    
  240.     X#endif
  241.     X    exit (0);
  242.     X    }
  243.     X
  244.     X/*-------------------------------------------------------------05/23/88-+
  245.     X|                                    |
  246.     X|     build_offset : build offset from 1st line of ps output        |
  247.     X|                                    |
  248.     X+----------------------------------------------------------------------*/
  249.     Xbuild_offset (buf)
  250.     Xchar    *buf;                /* header line */
  251.     X    {
  252.     X    char        *p = buf;
  253.     X    for (p=buf; *p != '\0'; p++) {
  254.     X        if      (strncmp ("UID",    p, 3) == 0) Uid_offset     = p-buf;
  255.     X        else if (strncmp ("  PID ", p, 6) == 0) Pid_offset     = p-buf;
  256.     X        else if (strncmp (" PPID ", p, 6) == 0) Ppid_offset    = p-buf;
  257.     X        else if (strncmp ("STAT",   p, 4) == 0) Stat_offset    = p-buf;
  258.     X        else if (strncmp ("TTY",    p, 3) == 0) Tyy_offset     = p-buf;
  259.     X        else if (strncmp ("COMMAND",p, 7) == 0) Command_offset = p-buf;
  260.     X        }
  261.     X    End_ppid = Ppid_offset + 5;
  262.     X    }
  263.     X
  264.     X/*-------------------------------------------------------------05/23/88-+
  265.     X|                                    |
  266.     X|       save_addr : return addr of Save array with pid = pid        |
  267.     X|                                    |
  268.     X+----------------------------------------------------------------------*/
  269.     Xstruct    save    *
  270.     Xsave_addr (pid)
  271.     Xint    pid;
  272.     X    {
  273.     X    register int    i;
  274.     X    for (i=1; i<Line; i++) {
  275.     X        if (Save[i].so_pid == pid) return (&Save[i]);
  276.     X        }
  277.     X    return (NULL);            /* not found */
  278.     X    }
  279.     X
  280.     X/*-------------------------------------------------------------05/23/88-+
  281.     X|                                    |
  282.     X|  add_child : add child to parent, if exists, add to end of sibling    |
  283.     X|                                    |
  284.     X+----------------------------------------------------------------------*/
  285.     Xadd_child (parent, child)
  286.     Xstruct    save    *parent;
  287.     Xstruct    save    *child;
  288.     X    {
  289.     X    if (parent->so_child == NULL) {
  290.     X        parent->so_child = child;
  291.     X        }
  292.     X    else    {
  293.     X        struct    save    *tp = parent->so_child;
  294.     X        while (tp->so_sibling != NULL) tp = tp->so_sibling;
  295.     X        tp->so_sibling = child;
  296.     X        }
  297.     X    child->so_sibling = NULL;
  298.     X    }
  299.     X
  300.     X/*-------------------------------------------------------------05/23/88-+
  301.     X|                                    |
  302.     X|              print_result : display result            |
  303.     X|                                    |
  304.     X+----------------------------------------------------------------------*/
  305.     Xprint_result ()
  306.     X    {
  307.     X    register int    i;
  308.     X    struct    save    *svp;
  309.     X
  310.     X    My_pid = getpid ();
  311.     X    printf ("%s    USER %s", Print_pid ? "  PID " : "",
  312.     X        &Save[0].so_buffer[Stat_offset]);
  313.     X    for (i=1; i<Line; i++) {
  314.     X        svp = &Save[i];
  315.     X        if (svp->so_parent != NULL) {
  316.     X            if (svp->so_pid != 0)
  317.     X              continue;
  318.     X            }
  319.     X        print_process (0, svp);
  320.     X        }
  321.     X    }
  322.     X
  323.     X/*-------------------------------------------------------------05/23/88-+
  324.     X|                                    |
  325.     X|          print_process : print a given process sub-tree        |
  326.     X|                                    |
  327.     X+----------------------------------------------------------------------*/
  328.     Xprint_process (level, svp)
  329.     Xint        level;
  330.     Xstruct    save    *svp;
  331.     X    {
  332.     X    struct    save    *tp;
  333.     X    register int    i;
  334.     X
  335.     X    if (!Print_me && svp->so_pid == My_pid) return;
  336.     X    if (Print_pid) printf ("%5d ", svp->so_pid);
  337.     X    printf ("%8s %.*s", svp->so_name, Command_offset - Stat_offset,
  338.     X        &svp->so_buffer[Stat_offset]);
  339.     X    for (i=0; i<level; i++) printf ("|  ");
  340.     X    printf ("%s", &svp->so_buffer[Command_offset]);
  341.     X    if ((tp = svp->so_child) != NULL) {
  342.     X        while (tp != NULL) {
  343.     X            if (tp != svp)        /* avoid infinit recursion */
  344.     X                print_process (level+1, tp);
  345.     X            tp = tp->so_sibling;
  346.     X            }
  347.     X        }
  348.     X    }
  349.     X
  350.     X/*-------------------------------------------------------------05/23/88-+
  351.     X|                                    |
  352.     X|          dump_save : dump save structure for debugging        |
  353.     X|                                    |
  354.     X+----------------------------------------------------------------------*/
  355.     X#ifdef    DEBUG
  356.     Xdump_save ()
  357.     X    {
  358.     X    register int        i;
  359.     X    register struct    save    *tp;
  360.     X
  361.     X    for (i=1; i<Line; i++) {
  362.     X        tp = &Save[i];
  363.     X        printf ("parent=%08x(x) ", tp->so_parent);
  364.     X        printf ("sibling=%08x(x) ", tp->so_sibling);
  365.     X        printf ("child=%08x(x) ", tp->so_child);
  366.     X        printf ("PID=%05d PPID=%05d\n", tp->so_pid, tp->so_ppid);
  367.     X        }
  368.     X    printf ("command: [%s]\n", Command);
  369.     X    }
  370.     X#endif
  371.     X
  372.     X/*------------------------------------------------------------05/24/88--+
  373.     X|                                    |
  374.     X|       procarg : return command argument for ps command        |
  375.     X|                                    |
  376.     X+----------------------------------------------------------------------*/
  377.     Xchar    *
  378.     Xprocarg (argc, argv)
  379.     Xint    argc;
  380.     Xchar    **argv;
  381.     X    {
  382.     X    static    char    buf [20] = "";
  383.     X    register char    c;
  384.     X    register char    *p = argv[1];
  385.     X    int        i = 0;
  386.     X
  387.     X    if (argc == 1) return (buf);
  388.     X    while ((c = *p++) != '\0') {
  389.     X        switch (c) {
  390.     X            case 'P':    Print_me = YES;        break;
  391.     X            case 'p':    Print_pid = YES;    break;
  392.     X            case 'H':    usage (argv[0]);    exit (0);
  393.     X            case 'a': case 'c': case 'e': case 'g':
  394.     X            case 'x':    buf[i++] = c;        break;
  395.     X            case 't':    strcpy (&buf[i], p-1);    return (buf);
  396.     X            default:    usage (argv[0]); exit (1);
  397.     X            }
  398.     X        }
  399.     X    buf [i] = '\0';
  400.     X    return (buf);
  401.     X    }
  402.     X
  403.     X/*-------------------------------------------------------------07/01/86-+
  404.     X|                                    |
  405.     X|            usage : display help message            |
  406.     X|                                    |
  407.     X+----------------------------------------------------------------------*/
  408.     Xstatic usage (pname)
  409.     Xchar    *pname;            /* program name */
  410.     X    {
  411.     X    fprintf (stderr, "%s  %s  %s\n", pname, Version, Author);
  412.     X    fprintf (stderr, "Usage: %s [acepgtxHP]\n", pname);
  413.     X    fprintf (stderr, "where options:\n");
  414.     X    fprintf (stderr, "  H              display this help message\n");
  415.     X    fprintf (stderr, "  P              print processes created by me\n");
  416.     X    fprintf (stderr, "  p              output PID\n");
  417.     X    fprintf (stderr, "  a,c,e,g,t,x    will be passed to ps, if t is\n");
  418.     X    fprintf (stderr, "                 specified, all the rest char in\n");
  419.     X    fprintf (stderr, "                 the argument will be copied\n");
  420.     X    }
  421. SHAR_EOF
  422. if test 8883 -ne "`wc -c < 'ptree.c'`"
  423. then
  424.     echo shar: error transmitting "'ptree.c'" '(should have been 8883 characters)'
  425. fi
  426. fi # end of overwriting check
  427. echo shar: extracting "'Kill'" '(2925 characters)'
  428. if test -f 'Kill'
  429. then
  430.     echo shar: will not over-write existing file "'Kill'"
  431. else
  432. sed 's/^    X//' << \SHAR_EOF > 'Kill'
  433.     X#! /bin/csh -f
  434.     X#
  435.     X#-    Kill - kill process with shell form interface
  436.     X#-
  437.     X#-    This  program will use  shell form to   display current user's
  438.     X#-    process  generated by  ptree command.    You  can  tab to  the
  439.     X#-    desired process  and select proper signal to  be  sent  to the
  440.     X#-    process.  Press return will trigger the action.
  441.     X#-
  442.     X#    Author:        Paul Lew, General Systems Group, Inc.
  443.     X#    Created at:    05/12/88  07:56 PM
  444.     X#    Last update:    07/26/88  10:56 AM  (Edition: 32)
  445.     X#
  446.     X#-    Usage:        Kill [string]
  447.     X#-    where option:
  448.     X#-        string    if specified, will do 'ptree ax | grep string'
  449.     X#-            and display only matched process.
  450.     X#
  451.     Xset tmpfile = "/tmp/tmpfile.$$"
  452.     Xset sofile = "/tmp/sofile.$$"
  453.     Xset ptfile = "/tmp/ptfile.$$"
  454.     X#---------------------------------------------------------------#
  455.     X#          Display help if requested by user            #
  456.     X#---------------------------------------------------------------#
  457.     Xswitch ( "$1" )
  458.     X    case -H[xX]:
  459.     X        set echo; set verbose; shift
  460.     X        breaksw
  461.     X    case -H*:
  462.     X        show_help `which $0` $1
  463.     X        goto end
  464.     X    default:
  465.     X    endsw
  466.     X#---------------------------------------------------------------#
  467.     X#            Process Arguments            #
  468.     X#---------------------------------------------------------------#
  469.     Xset greparg = '.'
  470.     Xset ptflag = 'x'
  471.     Xif ( "$1" != '' ) then
  472.     X    set greparg = $1
  473.     X    set ptflag = 'ax'
  474.     X    endif
  475.     X#---------------------------------------------------------------#
  476.     X#          Create sf description file            #
  477.     X#---------------------------------------------------------------#
  478.     Xpt p$ptflag > $tmpfile
  479.     Xtr '~' '?' < $tmpfile | sed -n \
  480.     X   -e '1s/COMMAND/SIGNAL &/p;1d' \
  481.     X   -e  '/Kill/d' \
  482.     X   -e "/$greparg/"'{;s/^\(..............................\)\(.*\)$/\1~~~~~~ \2/p;}' \
  483.     X   > $ptfile
  484.     Xsed 's/^......//' $ptfile | colrm 80 > $tmpfile
  485.     X@ lcount = `cat $tmpfile | wc -l`
  486.     X@ lcount--
  487.     Xif ( $lcount == 0 ) then
  488.     X    echo "...Pattern $greparg not found in pt list, aborted..."
  489.     X    goto end
  490.     X    endif
  491.     Xcat << cat_eof >> $tmpfile
  492.     X
  493.     X[TAB (next process), SPACE (next signal), - (no signal), RETURN (execute)]
  494.     X
  495.     Xcat_eof
  496.     X@ i = 0
  497.     Xset sig = "/-     /HUP/INT/QUIT/ILL/TRAP/ABRT/EMT/FPE/KILL/BUS/SEGV/SYS"
  498.     Xset sig = "$sig/PIPE/ALRM/TERM/URG/STOP/TSTP/CONT/CHLD/TTIN/TTOU/IO/XCPU"
  499.     Xset sig = "$sig/XFSZ/VTALRM/PROF/USR1/USR2/PWR/LOST/"
  500.     Xwhile ( $i < $lcount )
  501.     X    @ i++
  502.     X    echo ".v=var$i.s=$sig." >> $tmpfile
  503.     X    end
  504.     X#---------------------------------------------------------------#
  505.     X#           run sf to get user input            #
  506.     X#---------------------------------------------------------------#
  507.     Xsf -u -o $sofile < $tmpfile
  508.     Xif ( ! -e $sofile ) goto end
  509.     Xsource $sofile
  510.     X@ i = 0
  511.     Xwhile ( $i < $lcount )
  512.     X    @ i++
  513.     X    set var = `eval echo \$var$i`
  514.     X    if ( "$var" != '-' ) then
  515.     X        @ line = $i + 1
  516.     X        kill -$var `sed -n "$line"'s/^ *\([0-9]*\).*$/\1/p' $ptfile`
  517.     X        endif
  518.     X    end
  519.     X#---------------------------------------------------------------#
  520.     X#        Clean up and exit here...            #
  521.     X#---------------------------------------------------------------#
  522.     Xend:
  523.     X    /bin/rm -f $tmpfile $sofile $ptfile
  524.     X    unset tmpfile sofile ptfile i lcount var line greparg ptflag
  525. SHAR_EOF
  526. if test 2925 -ne "`wc -c < 'Kill'`"
  527. then
  528.     echo shar: error transmitting "'Kill'" '(should have been 2925 characters)'
  529. fi
  530. fi # end of overwriting check
  531. #    End of shell archive
  532. exit 0
  533.